import pandas as pd
import numpy as np
import os
from sklearn.utils import shuffle
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from datetime import datetime
from dateutil.relativedelta import relativedelta
import json
import calendar
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)

# 读取 JSON 文件
with open('config.json', 'r') as file:
    config = json.load(file)

# 提取顶层参数
data_path = config["data_path"]
output_path = config["output_path"]
test_size = config["test_size"]
random_state_start = config["random_state_start"]
i_dd = config["i_dd"]

# 提取模型的参数
# DecisionTreeRegressor 参数
dt_max_depth = config["models"]["DecisionTreeRegressor"]["max_depth"]
dt_random_state = config["models"]["DecisionTreeRegressor"]["random_state"]

# SVR 参数
svr_C = config["models"]["SVR"]["C"]
svr_epsilon = config["models"]["SVR"]["epsilon"]

# KNeighborsRegressor 参数
knn_n_neighbors = config["models"]["KNeighborsRegressor"]["n_neighbors"]

# RandomForestRegressor 参数
rf_n_estimators = config["models"]["RandomForestRegressor"]["n_estimators"]
rf_max_depth = config["models"]["RandomForestRegressor"]["max_depth"]
rf_random_state = config["models"]["RandomForestRegressor"]["random_state"]

# BaggingRegressor 参数
br_n_estimators = config["models"]["BaggingRegressor"]["n_estimators"]
br_max_samples = config["models"]["BaggingRegressor"]["max_samples"]
br_max_features = config["models"]["BaggingRegressor"]["max_features"]
br_random_state = config["models"]["BaggingRegressor"]["random_state"]

# XGBRegressor 参数
xgb_objective = config["models"]["XGBRegressor"]["objective"]
xgb_n_estimators = config["models"]["XGBRegressor"]["n_estimators"]
xgb_learning_rate = config["models"]["XGBRegressor"]["learning_rate"]
xgb_max_depth = config["models"]["XGBRegressor"]["max_depth"]
xgb_min_child_weight = config["models"]["XGBRegressor"]["min_child_weight"]
xgb_subsample = config["models"]["XGBRegressor"]["subsample"]
xgb_gamma = config["models"]["XGBRegressor"]["gamma"]
xgb_colsample_bytree = config["models"]["XGBRegressor"]["colsample_bytree"]
xgb_reg_alpha = config["models"]["XGBRegressor"]["reg_alpha"]
xgb_reg_lambda = config["models"]["XGBRegressor"]["reg_lambda"]
xgb_random_state = config["models"]["XGBRegressor"]["random_state"]


from sklearn import tree
model_DecisionTreeRegressor = tree.DecisionTreeRegressor(max_depth=dt_max_depth, random_state=dt_random_state)
from sklearn import svm
model_SVR = svm.SVR()
from sklearn import neighbors
model_KNeighborsRegressor = neighbors.KNeighborsRegressor(n_neighbors=knn_n_neighbors)
from sklearn import ensemble
model_RandomForestRegressor = ensemble.RandomForestRegressor(n_estimators=rf_n_estimators, max_depth=rf_max_depth,
                                                             random_state=rf_random_state)
from sklearn.ensemble import BaggingRegressor
model_BaggingRegressor = BaggingRegressor(n_estimators=br_n_estimators, max_samples=br_max_samples,
                                          max_features=br_max_features, random_state=br_random_state)
from xgboost import XGBRegressor
model_XGBRegressor = XGBRegressor(objective=xgb_objective, n_estimators=xgb_n_estimators,
                                  learning_rate=xgb_learning_rate, max_depth=xgb_max_depth,
                                  min_child_weight=xgb_min_child_weight,
                         subsample=xgb_subsample, gamma=xgb_gamma, colsample_bytree=xgb_colsample_bytree,
                                  reg_alpha=xgb_reg_alpha, reg_lambda=xgb_reg_lambda,random_state=xgb_random_state )


start_date=""                 #(形式为yyyy-mm-dd)




def get_score(result, y_test, model_name):
    score = r2_score(y_test, result)

    rmse = mean_squared_error(y_test, result) ** 0.5
    MAE = mean_absolute_error(y_test, result)
    MAPE = (abs((y_test - result) / y_test)).mean() * 100.0

    return rmse, MAE, MAPE, score


io = data_path
data_all =pd.read_excel(io)
merge_data = data_all.copy()
train_x = merge_data.iloc[:, :-1]
train_y = merge_data.iloc[:, -1]


df_y_test = []
df_y_test_index = []
Feature = []
CART_shuzu = {}
measure = []
CART_pre_result = []
canshu_CART = pd.DataFrame(columns=['RMSE', 'MAE', 'MAPE', 'R2'])
SVM_shuzu = {}
SVM_pre_result = []
canshu_SVR = pd.DataFrame(columns=['RMSE', 'MAE', 'MAPE', 'R2'])
KNN_shuzu = {}
KNN_pre_result = []
canshu_KNN = pd.DataFrame(columns=['RMSE', 'MAE', 'MAPE', 'R2'])
RF_shuzu = {}
RF_pre_result = []
RF_feature = []
canshu_RF = pd.DataFrame(columns=['RMSE', 'MAE', 'MAPE', 'R2'])
BAG_shuzu = {}
BAG_pre_result = []
canshu_Bag = pd.DataFrame(columns=['RMSE', 'MAE', 'MAPE', 'R2'])
XGB_shuzu = {}
XGB_pre_result = []
XGB_feature = []
canshu_xgb = pd.DataFrame(columns=['RMSE', 'MAE', 'MAPE', 'R2'])



for i in range(i_dd):
    X_train, X_test, y_train, y_test = train_test_split(train_x, train_y, test_size=0.2,random_state=i)
    df_y_test.append(y_test.values)
    df_y_test_index.append(y_test.index)
    ##########CART#################
    model_DecisionTreeRegressor.fit(X_train,y_train)
    cart_result = model_DecisionTreeRegressor.predict(X_test)
    x,y,z,r = get_score(cart_result,y_test,'CART')
    if r > 0:
        CART_pre_result.append(cart_result)
        CART_shuzu = {'RMSE': x, 'MAE': y, 'MAPE': z, 'R2': r}
        CART_shuzu_df = pd.DataFrame([CART_shuzu])
        canshu_CART = pd.concat([canshu_CART, CART_shuzu_df], ignore_index=True)
    #########SVM#################
    model_SVR.fit(X_train,y_train)
    svr_result = model_SVR.predict(X_test)
    x,y,z,r = get_score(svr_result,y_test,'SVR')
    if r > 0:
        SVM_pre_result.append(svr_result)
        SVM_shuzu = {'RMSE': x, 'MAE': y, 'MAPE': z, 'R2': r}
        SVM_shuzu_df = pd.DataFrame([SVM_shuzu])
        canshu_SVR = pd.concat([canshu_SVR, SVM_shuzu_df], ignore_index=True)
    ##########KNN#################
    model_KNeighborsRegressor.fit(X_train,y_train)
    KNN_result = model_KNeighborsRegressor.predict(X_test)
    x,y,z,r = get_score(KNN_result,y_test,'KNN')
    if r > 0:
        KNN_pre_result.append(KNN_result)
        KNN_shuzu = {'RMSE': x, 'MAE': y, 'MAPE': z, 'R2': r}
        KNN_shuzu_df = pd.DataFrame([KNN_shuzu])
        canshu_KNN = pd.concat([canshu_KNN, KNN_shuzu_df], ignore_index=True)
    ##########RF#################
    model_RandomForestRegressor.fit(X_train,y_train)
    RF_result = model_RandomForestRegressor.predict(X_test)
    x,y,z,r = get_score(RF_result,y_test,'RF')
    if r > 0:
        RF_pre_result.append(RF_result)
        RF_feature.append(model_RandomForestRegressor.feature_importances_)
        RF_shuzu = {'RMSE': x, 'MAE': y, 'MAPE': z, 'R2': r}
        RF_shuzu_df = pd.DataFrame([RF_shuzu])
        canshu_RF = pd.concat([canshu_RF, RF_shuzu_df], ignore_index=True)
    ##########BAG#################
    model_BaggingRegressor.fit(X_train,y_train)
    Bagging_result = model_BaggingRegressor.predict(X_test)
    x,y,z,r = get_score(Bagging_result,y_test,'Bagging')
    if r > 0:
        BAG_pre_result.append(Bagging_result)
        BAG_shuzu = {'RMSE': x, 'MAE': y, 'MAPE': z, 'R2': r}
        BAG_shuzu_df = pd.DataFrame([BAG_shuzu])
        canshu_Bag = pd.concat([canshu_Bag, BAG_shuzu_df], ignore_index=True)
    ##########XGB#################
    model_XGBRegressor.fit(X_train, y_train)
    xgb_result=model_XGBRegressor.predict(X_test)
    x,y,z,r = get_score(xgb_result,y_test,'xgb')
    if r > 0:
        XGB_pre_result.append(xgb_result)
        XGB_feature.append(model_XGBRegressor.feature_importances_)
        XGB_shuzu = {'RMSE': x, 'MAE': y, 'MAPE': z, 'R2': r}
        XGB_shuzu_df = pd.DataFrame([XGB_shuzu])
        canshu_xgb = pd.concat([canshu_xgb, XGB_shuzu_df], ignore_index=True)
pre_y_test = pd.DataFrame(df_y_test)
pre_y_test_index = pd.DataFrame(df_y_test_index)
FIN_CART_pre_result = pd.DataFrame(CART_pre_result)
FIN_SVM_pre_result = pd.DataFrame(SVM_pre_result)
FIN_KNN_pre_result = pd.DataFrame(KNN_pre_result)
FIN_RF_pre_result = pd.DataFrame(RF_pre_result)
FIN_BAG_pre_result = pd.DataFrame(BAG_pre_result)
FIN_XGB_pre_result = pd.DataFrame(XGB_pre_result)
RF_feature_wight = pd.DataFrame(RF_feature)
XGB_feature_wight = pd.DataFrame(XGB_feature)
Feature.append(np.mean(RF_feature,axis=0))
Feature.append(np.mean(XGB_feature,axis=0))
Feature_wight = pd.DataFrame(Feature)
Feature_wight.columns = train_x.columns
Feature_wight.index = ['RF', 'XGB']







def get_score(result, y_test, model_name):
    score = r2_score(y_test, result)

    rmse = mean_squared_error(y_test, result) ** 0.5
    MAE = mean_absolute_error(y_test, result)
    # MAPE = (abs((y_test - result)/y_test)).mean()*100.0

    return rmse, MAE, score


train = []
X_train, X_test, y_train, y_test = train_test_split(train_x, train_y, test_size=0.5, random_state=171)
train.extend(y_train)
train.extend(y_test)
measure = pd.concat([y_train, y_test], axis=0)
# 保存合并后的目标值
measure_file = os.path.join(output_path, 'measure.xlsx')
measure.to_excel(measure_file, index=False)

########## CART #################
model_DecisionTreeRegressor.fit(X_train, y_train)
cart_train_result = pd.DataFrame(model_DecisionTreeRegressor.predict(X_train), columns=['预测值'])
cart_result = pd.DataFrame(model_DecisionTreeRegressor.predict(X_test), columns=['预测值'])
x, y, z = get_score(cart_result['预测值'], y_test, 'CART')
CART_pre_result = pd.concat([cart_train_result, cart_result], axis=0)
CART_file = os.path.join(output_path, 'CART_pre_result.xlsx')
CART_pre_result.to_excel(CART_file, index=False)
CART_shuzu = {'RMSE': x, 'MAE': y, 'R2': z}


########## SVR #################
model_SVR.fit(X_train, y_train)
svr_train_result = pd.DataFrame(model_SVR.predict(X_train), columns=['预测值'])
svr_result = pd.DataFrame(model_SVR.predict(X_test), columns=['预测值'])
x, y, z = get_score(svr_result['预测值'], y_test, 'SVR')
SVM_pre_result = pd.concat([svr_train_result, svr_result], axis=0)
SVR_file = os.path.join(output_path, 'SVR_pre_result.xlsx')
SVM_pre_result.to_excel(SVR_file, index=False)
SVM_shuzu = {'RMSE': x, 'MAE': y, 'R2': z}


########## KNN #################
model_KNeighborsRegressor.fit(X_train, y_train)
KNN_train_result = pd.DataFrame(model_KNeighborsRegressor.predict(X_train), columns=['预测值'])
KNN_result = pd.DataFrame(model_KNeighborsRegressor.predict(X_test), columns=['预测值'])
x, y, z = get_score(KNN_result['预测值'], y_test, 'KNN')
KNN_pre_result = pd.concat([KNN_train_result, KNN_result], axis=0)
KNN_file = os.path.join(output_path, 'KNN_pre_result.xlsx')
KNN_pre_result.to_excel(KNN_file, index=False)
KNN_shuzu = {'RMSE': x, 'MAE': y, 'R2': z}

########## RF #################
model_RandomForestRegressor.fit(X_train, y_train)
RF_train_result = pd.DataFrame(model_RandomForestRegressor.predict(X_train), columns=['预测值'])
RF_result = pd.DataFrame(model_RandomForestRegressor.predict(X_test), columns=['预测值'])
x, y, z = get_score(RF_result['预测值'], y_test, 'RF')
RF_pre_result = pd.concat([RF_train_result, RF_result], axis=0)
RF_file = os.path.join(output_path, 'RF_pre_result.xlsx')
RF_pre_result.to_excel(RF_file, index=False)
RF_shuzu = {'RMSE': x, 'MAE': y, 'R2': z}


########## BAG #################
model_BaggingRegressor.fit(X_train, y_train)
Bagging_train_result = pd.DataFrame(model_BaggingRegressor.predict(X_train), columns=['预测值'])
Bagging_result = pd.DataFrame(model_BaggingRegressor.predict(X_test), columns=['预测值'])
x, y, z = get_score(Bagging_result['预测值'], y_test, 'Bagging')
BAG_pre_result = pd.concat([Bagging_train_result, Bagging_result], axis=0)
BAG_file = os.path.join(output_path, 'Bagging_pre_result.xlsx')
BAG_pre_result.to_excel(BAG_file, index=False)
BAG_shuzu = {'RMSE': x, 'MAE': y, 'R2': z}


########## XGB #################
model_XGBRegressor.fit(X_train, y_train)
xgb_train_result = pd.DataFrame(model_XGBRegressor.predict(X_train), columns=['预测值'])
xgb_result = pd.DataFrame(model_XGBRegressor.predict(X_test), columns=['预测值'])
x, y, z = get_score(xgb_result['预测值'], y_test, 'XGB')
XGB_pre_result = pd.concat([xgb_train_result, xgb_result], axis=0)
XGB_file = os.path.join(output_path, 'XGB_pre_result.xlsx')
XGB_pre_result.to_excel(XGB_file, index=False)
XGB_shuzu = {'RMSE': x, 'MAE': y, 'R2': z}


# 定义模型文件路径
measure_file = os.path.join(output_path, 'measure.xlsx')
cart_file = os.path.join(output_path, 'CART_pre_result.xlsx')
svr_file = os.path.join(output_path, 'SVR_pre_result.xlsx')
knn_file = os.path.join(output_path, 'KNN_pre_result.xlsx')
rf_file = os.path.join(output_path, 'RF_pre_result.xlsx')
bagging_file = os.path.join(output_path, 'Bagging_pre_result.xlsx')
xgb_file = os.path.join(output_path, 'XGB_pre_result.xlsx')

# 1. 汇总所有模型的平均 RMSE
models_metrics = {
    'CART': canshu_CART['RMSE'].mean(),
    'SVR': canshu_SVR['RMSE'].mean(),
    'KNN': canshu_KNN['RMSE'].mean(),
    'RF': canshu_RF['RMSE'].mean(),
    'Bagging': canshu_Bag['RMSE'].mean(),
    'xgb': canshu_xgb['RMSE'].mean()
}

metrics_df = pd.DataFrame(list(models_metrics.items()), columns=['模型', '平均RMSE'])


# 2. 选择 RMSE 最低的模型
best_model_row = metrics_df.loc[metrics_df['平均RMSE'].idxmin()]
best_model_name = best_model_row['模型']
best_model_rmse = best_model_row['平均RMSE']

# 假设 start_date 是一个 datetime 对象
new_start_date = datetime.strptime(start_date, '%Y-%m-%d')

# 获取下一个月的年份和月份
next_month = new_start_date + relativedelta(months=1)

# 获取下一个月的天数
_, days_in_next_month = calendar.monthrange(next_month.year, next_month.month)




# 3. 根据最佳模型名称，读取对应的 Excel 文件并打印内容
if best_model_name == 'Bagging':
    # 定义 Bagging 模型的预测结果文件名
    Bagging_file = os.path.join(output_path, 'Bagging_pre_result.xlsx')

    # 检查文件是否存在
    if os.path.exists(bagging_file):
        # 读取 Excel 文件
        bagging_df = pd.read_excel(bagging_file)

        # 创建逐日递增的时间序列
        bagging_df['日期'] = pd.date_range(start=start_date, periods=len(bagging_df), freq='D')

        # 将日期列移到最前面
        bagging_df = bagging_df[['日期'] + [col for col in bagging_df.columns if col != '日期']]
        # 选择输出的预测结果
        if next_month.month == 2:
            # 从倒数第三行开始，向前取 `days_in_next_month` 个数据
            selected_data = bagging_df.iloc[-2 - days_in_next_month: -2]
        else:
            # 打印输出结果
            selected_data = bagging_df.tail(days_in_next_month)

        # 输出到控制台
        print("最佳模型 (Bagging) 的预测结果数组：")
        print(selected_data.to_string(index=False))

        # 将结果保存到新的 Excel 文件
        output_file = os.path.join(output_path, 'predictions_output.xlsx')
        selected_data.to_excel(output_file, index=False)
    else:
        print(f"文件 {bagging_file} 不存在。请确保 Bagging 模型的预测结果已保存为该文件。")
else:
    # 对于其他模型，按需定义文件名并读取
    other_model_file = os.path.join(output_path, f'{best_model_name}_pre_result.xlsx')

    if os.path.exists(other_model_file):
        other_df = pd.read_excel(other_model_file)
        other_df['日期'] = pd.date_range(start=start_date, periods=len(other_df), freq='D')
        other_df = other_df[['日期'] + [col for col in other_df.columns if col != '日期']]
        if next_month.month == 2:
            # 从倒数第三行开始，向前取 `days_in_next_month` 个数据
            selected_data = other_df.iloc[-2 - days_in_next_month: -2]
        else:
            # 打印输出结果
            selected_data = other_df.tail(days_in_next_month)

        # 输出到控制台
        print("最佳模型 ({best_model_name}) 的预测结果数组：")
        print(selected_data.to_string(index=False))

        # 将结果保存到新的 Excel 文件
        output_file = os.path.join(output_path, 'predictions_output.xlsx')
        selected_data.to_excel(output_file, index=False)
    else:
        print(f"文件 {other_model_file} 不存在。请确保 {best_model_name} 模型的预测结果已保存为该文件。")